<template>
  <page-meta :root-font-size="fontSize + 'px'"></page-meta>

  <view class="page-container">
    <CustomHeader :bgcolor="compatibleModule.topHeaderBgColor" :back-method="popupModule.handleOpenBackModal" title="随课自检" :border-line="false" />

    <view
      class="total-time-container"
      :style="{
        height: compatibleModule.excessHeight,
        backgroundColor: compatibleModule.topHeaderBgColor,
      }"
    >
      <view class="time">
        <text class="prefix">已用时</text>
        <CountTime v-model:seconds="popupModule.useTime"></CountTime>
      </view>
      <view class="total">
        <text class="prefix">总进度</text>
        <view class="right">
          <text class="current">{{ popupModule.currentIndex + 1 }}</text>
          <text class="sum">/{{ Course.queryParams.totalProgress }}</text>
        </view>
      </view>
    </view>

    <view class="scene-container" :style="{ top: `calc(${height} + ${compatibleModule.excessHeight})` }">
      <!--   播放器   -->
      <text class="top-hint">请听音频, 选择符合题意的选项作答</text>
      <view class="audio-container">
        <view class="progress">
          <CustomProgress
            :max="audioModule.progress.maxvalue"
            @on-touch-click="audioModule.setPlayProgress"
            @on-touch-move="audioModule.onTouchMove"
            @on-touch-end="audioModule.onTouchEnd"
            :current="audioModule.progress.currentValue"
          >
            <template #first>
              <view class="time">{{ audioModule.pageView.currentTime }}</view>
            </template>
            <template #last>
              <view class="time">{{ audioModule.pageView!.totalTime }}</view>
            </template>
          </CustomProgress>
        </view>
        <view class="operation">
          <view class="button speed-back" @click="audioModule.handleRewind(false, 5)">
            <image class="icon" src="https://rwstatic.tentons.cn/web/Lesson/images/refresh-icon-yellow.png"> </image>
            <text class="text">5</text>
          </view>
          <view class="play">
            <image
              v-show="!audioModule.isPlaying"
              @click="audioModule.handleChangeAudioStatus(true)"
              class="icon"
              src="https://rwstatic.tentons.cn/web/Lesson/images/operation/pause-icon.png"
            >
            </image>
            <image
              v-show="audioModule.isPlaying"
              @click="audioModule.handleChangeAudioStatus(false)"
              class="icon"
              src="https://rwstatic.tentons.cn/web/Lesson/images/operation/play-icon.png"
            >
            </image>
          </view>
          <view class="button" @click="audioModule.handleRewind(true, 5)">
            <image class="icon" src="https://rwstatic.tentons.cn/web/Lesson/images/refresh-icon-yellow.png"> </image>
            <text class="text">5</text>
          </view>
          <view @click="audioModule.handleChangeSpeed" class="speed-select">
            {{ audioModule.pageView!.speedText }}
          </view>
        </view>
      </view>

      <view
        :style="{
          maxHeight: `calc(100vh - ${height} - ${compatibleModule.excessHeight})`,
          height: compatibleModule.sidePopupHeight,
          minHeight: compatibleModule.minHeight,
        }"
      >
      </view>
    </view>

    <template v-if="popupModule.selectList.length && popupModule.currentIndex + 1 == popupModule.selectList.length">
      <view @click="popupModule.handleOpenSubmitModal" class="submit-button">
        <text>选词填空</text>
      </view>
    </template>

    <template v-if="popupModule.selectList.length">
      <DragSidePopup
        swiperStyle
        :excess-height="compatibleModule.excessHeight"
        v-model:height="compatibleModule.sidePopupHeight"
        :min-height="compatibleModule.minHeight"
      >
        <template #header>
          <view class="select-header">
            <view class="left">
              <template v-for="(item, index) in popupModule.selectList" :key="index">
                <view :class="['item', getSideTopClass(index)]" @click="popupModule.handleChangeSwiper({ detail: { current: index } })"></view>
              </template>
            </view>
            <view class="right">
              <text class="current">{{ popupModule.currentIndex + 1 }}</text>
              <text class="total">/{{ popupModule.selectList.length }}</text>
            </view>
          </view>
        </template>
        <template #content>
          <swiper class="select-body" :current="popupModule.currentIndex" @change="popupModule.handleChangeSwiper" :autoplay="false">
            <template v-for="(parent, parentIndex) in popupModule.selectList" :key="parentIndex">
              <swiper-item class="swiper-item">
                <view class="serial_number">Question {{ parentIndex + 1 }}</view>
                <view class="select-content">
                  <template v-for="(child, childIndex) in parent.options" :key="childIndex">
                    <view
                      :class="['item', popupModule.selectAnswer[parentIndex].answer == child.op_idx && 'active']"
                      @click="popupModule.handleClickItem(parentIndex, child.op_idx, parent.topic_id)"
                    >
                      <text class="number">{{ child.op_idx }}</text>
                      <text class="text">{{ child.option }}</text>
                    </view>
                  </template>
                </view>
              </swiper-item>
            </template>
          </swiper>
        </template>
      </DragSidePopup>
    </template>

    <CwCommon></CwCommon>
  </view>
</template>

<script lang="ts" setup>
import { reactive, ref, toRaw } from "vue";
import { onUnload } from "@dcloudio/uni-app";
import { rootFontSize, getFormatTime, util } from "@/utils/util";
import CustomHeader from "@/components/customHeader.vue";
import DragSidePopup from "@/components/dragSidePopup.vue";
import CountTime from "@/components/countTime.vue";
import CustomProgress from "@/components/customProgress.vue";
import env from "@/config/env";
import API from "@/api";
import { Course, CoursePageEnum } from "./index";
import { getAnyApp } from "@/common/hooks";

type Partial<T> = { [P in keyof T]?: T[P] };
type ProgressType = { maxvalue: number; currentValue: number };
interface AudioModule {
  config: Partial<UniApp.InnerAudioContext>;
  isPlaying: boolean;
  isPaused: boolean;
  progress: ProgressType;
  isReadyPlay: boolean;
  pageView: any;
  init(): void;
  handleChangeAudioStatus(params: boolean): void;
  handleChangeSpeed(): void;
  handleRewind(forward: boolean, time: number): void;
  setPlayProgress(value: number): void;
  destroy(): void;
  onCanplay(): void;
  onTouchMove(e: any): void;
  onTouchEnd(e: any): void;
}

// 公用常量
const { CHEESE } = getAnyApp();

const fontSize = rootFontSize();

const height = ref(getApp().globalData!.pageTop);

/**
 * 音频播放模块
 */
const audioContext = uni.createInnerAudioContext();
const audioModule = reactive<AudioModule>({
  config: {
    autoplay: true,
    src: "",
  },
  isPaused: false,
  isPlaying: false,
  isReadyPlay: false,
  progress: {
    maxvalue: 0,
    currentValue: 0,
  },
  pageView: {
    currentTime: "00:00",
    totalTime: "00:00",
    speedValue: ["0.8", "1.0", "1.25"],
    speedText: "1.0X",
  },
  init() {
    for (let key in this.config) {
      (audioContext as any)[key] = (this.config as any)[key];
    }

    this.onCanplay();
    wx.setInnerAudioOption({ obeyMuteSwitch: false }); //手机静音仍然可播放
    audioContext.onTimeUpdate(() => {
      if (this.isPaused) return;
      this.progress.currentValue = audioContext.currentTime;
      this.pageView.currentTime = getFormatTime(audioContext.currentTime, "mm-ss");
    });

    //音频播放事件
    audioContext.onPlay(() => {
      this.isPlaying = true;
    });

    //音频播放事件
    audioContext.onPause(() => {
      this.isPlaying = false;
    });

    //音频自然播放结束事件
    audioContext.onEnded(() => {
      this.isPlaying = false;
      this.pageView.currentTime = this.pageView.totalTime;
    });

    audioContext.onError((res) => {
      uni.showToast({ title: "音频播放失败" });
    });
  },
  // 切换播放速度
  handleChangeSpeed() {
    let speed: string | number = audioContext.playbackRate || 1;
    let index = this.pageView.speedValue.findIndex((item: string) => parseFloat(item) == speed);

    if (index + 1 >= this.pageView.speedValue.length) speed = this.pageView.speedValue[0];
    else speed = this.pageView.speedValue[index + 1];

    let speedText;
    speed == "0.8" ? (speedText = "0.75") : (speedText = speed);

    this.pageView.speedText = speedText + "X";

    audioContext.playbackRate = parseFloat(speed as string);
    // 处理ios不能播放途中切换速度问题
    if (this.isPlaying) {
      this.handleChangeAudioStatus(false);
      this.handleChangeAudioStatus(true);
    }
  },
  // 暂停or开始
  handleChangeAudioStatus(isPlay: boolean) {
    isPlay ? audioContext.play() : audioContext.pause();
  },
  // 快进or快退
  handleRewind(forward: boolean, time: number) {
    if (!this.isReadyPlay) return;
    let value;
    if (forward) {
      value = parseInt(this.progress.currentValue as any) + time;
      this.setPlayProgress(value <= audioContext.duration ? value : audioContext.duration);
    } else {
      value = parseInt(this.progress.currentValue as any) - time;
      this.setPlayProgress(value >= 0 ? value : 0);
    }
  },
  //更改播放进度
  setPlayProgress(value) {
    audioContext.seek(value);
    audioModule.progress.currentValue = value;
    audioModule.pageView.currentTime = getFormatTime(value, "mm-ss");
  },
  onTouchMove(e: any) {
    audioModule.isPaused = true;
    audioModule.setPlayProgress(e);
  },
  onTouchEnd(e: any) {
    audioModule.isPaused = false;
    audioModule.setPlayProgress(e);
  },
  // 递归监听时长
  onCanplay() {
    let _this = this;
    function updateTime() {
      setTimeout(() => {
        let duration = audioContext.duration;
        if (duration == 0 || isNaN(duration)) {
          updateTime();
        } else {
          // 可以进行播放
          _this.isReadyPlay = true;
          _this.progress.maxvalue = audioContext.duration;
          _this.pageView.totalTime = getFormatTime(audioContext.duration, "mm-ss");
        }
      }, 100);
    }
    audioContext.onCanplay(updateTime);
  },
  // 销毁音频
  destroy() {
    if (audioContext) {
      audioContext.pause();
      audioContext.destroy();
    }
  },
});

/**
 * 弹窗数据模块
 */
const popupModule = reactive({
  useTime: 0,
  selectList: [],
  selectAnswer: [] as { topic_id: string | number; answer: string }[],
  currentIndex: 0,
  async init(callback?: Function) {
    try {
      const listenData: any = await API.getCourseAnswerData({
        section_id: Course.sectionId,
        content_id: Course.data[CoursePageEnum.LISTEN].content_id,
      });
      audioModule.config.src = env.prefixUrl + listenData.topicData.us_voice;
      this.selectList = listenData?.topicData?.topic || [];
      for (let i = 0; i < this.selectList.length; i++) {
        this.selectAnswer.push({
          topic_id: (this.selectList[i] as any).topic_id,
          answer: "",
        });
      }
    } catch (e) {
      console.error(e);
    } finally {
      callback && callback();
    }
  },
  handleChangeSwiper(e: any) {
    const {
      detail: { current },
    } = e;
    this.currentIndex = current;
  },
  handleClickItem(parentIndex: number, answer: string, topic_id: string | number) {
    this.selectAnswer[parentIndex].topic_id = topic_id;
    this.selectAnswer[parentIndex].answer = answer;
  },
  handleOpenBackModal() {
    util.showModal({
      isShowModal: true,
      title: "现在退出不会保留进度,确定退出?",
      success: (e) => {
        uni.navigateBack({
          delta: 1,
        });
      },
    });
  },
  handleOpenSubmitModal() {
    util.showModal({
      isShowModal: true,
      title: "提交答案后不可更改, 确认提交吗",
      cancelBtnText: "再做会",
      confirmBtnText: "提交",
      success: async (e) => {
        try {
          let params = {
            section_id: Course.sectionId,
            content_id: Course.data[CoursePageEnum.LISTEN].content_id,
            time_long: popupModule.useTime,
            answer: toRaw(popupModule.selectAnswer),
          };
          await API.setCourseAnswerReport(params);
          CHEESE.Router.redirectTo({
            url: Course.data[CoursePageEnum.GAP].sourceUrl,
            params: {
              time: popupModule.useTime,
            },
          });
        } catch (e) {
          console.error(e);
        }
      },
    });
  },
});

// 兼容页面样式模块
const compatibleModule = reactive({
  sidePopupHeight: "35rem",
  minHeight: "15rem",
  excessHeight: "3rem",
  topHeaderBgColor: "#FDF2E0",
});

const getSideTopClass = (index: number) => {
  if (popupModule.currentIndex == index) return "current";
  if (popupModule.selectAnswer[index].answer) return "success";
};

onUnload(() => {
  audioModule.destroy();
});

(() => {
  popupModule.init(() => {
    audioModule.init();
  });
})();
</script>

<style scoped lang="scss">
@mixin fontStyle($size) {
  font-size: #{$size}rem;
  font-family: xiaolai;
  color: $uni-text-color;
}

.page-container {
  width: 100vw;
  height: 100vh;
  background-color: #fff;

  .total-time-container {
    @include fontStyle(1.6);
    display: flex;
    justify-content: center;
    align-items: flex-start;
    position: relative;
    border-bottom: 1px solid #eddcd7;
    box-sizing: border-box;

    .time {
      display: flex;
      align-items: center;

      .prefix {
        color: $uni-text-color-btn;
        margin-right: 0.5rem;
      }
    }

    .total {
      @include fontStyle(1.4);
      position: absolute;
      right: 20px;
      display: flex;
      align-items: center;

      .prefix {
        color: $uni-text-color-grey;
      }

      .right {
        text-align: right;
        width: 3rem;

        .current {
          color: $uni-text-color;
        }

        .sum {
          color: $uni-text-color-grey;
        }
      }
    }
  }

  .scene-container {
    width: 37.5rem;
    padding: 2rem 20px 20px 20px;
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    box-sizing: border-box;
    overflow-y: auto;

    .top-hint {
      @include fontStyle(1.5);
      color: $uni-text-color-grey;
    }

    /*播放器*/
    .audio-container {
      margin-top: 1rem;
      height: 15rem;
      border-radius: 2rem;
      border: 2px solid #d8ab60;
      padding: 2rem 1.4rem;
      box-sizing: border-box;
      background-color: #fff;

      .progress {
        .time {
          @include fontStyle(1.2);
          color: $uni-text-color-grey;
          width: 2.6rem;
        }
      }

      .operation {
        display: flex;
        align-items: center;
        justify-content: flex-end;
        margin-top: 3rem;

        .button {
          height: 3rem;
          width: 3rem;
          display: flex;
          align-items: center;
          justify-content: center;
          position: relative;

          .icon {
            height: 100%;
            width: 100%;
          }

          > .text {
            position: absolute;
            @include fontStyle(1.4);
            color: #d8ab60;
          }

          &.speed-back > .icon {
            transform: rotateY(180deg);
          }
        }

        .play {
          height: 5.4rem;
          width: 5.4rem;
          margin-left: 2.3rem;
          margin-right: 2.3rem;

          .icon {
            height: 100%;
            width: 100%;
          }
        }

        .speed-select {
          @include fontStyle(1.2);
          margin-left: 2.3rem;
          height: 2.2rem;
          width: 5.3rem;
          line-height: 2.2rem;
          border-radius: 1.25rem;
          text-align: center;
          border: 1px solid $uni-text-color;
          box-sizing: border-box;
        }
      }
    }
  }

  .submit-button {
    @include fontStyle(1.7);
    position: fixed;
    height: 5rem;
    width: 31.5rem;
    bottom: calc(2.5rem + constant(safe-area-inset-bottom));
    bottom: calc(2.5rem + env(safe-area-inset-bottom));
    line-height: 5rem;
    text-align: center;
    left: 50%;
    transform: translate(-50%);
    box-sizing: border-box;
    border: 0.2rem solid $uni-btn-border;
    background-color: $uni-btn-prime;
    border-radius: 1rem;
    z-index: 999;
  }

  /*选择框*/
  .select-header {
    display: flex;
    align-items: center;

    .left {
      flex: 1;
      display: flex;

      .item {
        flex: 1;
        background-color: #f9eedc;
        height: 0.6rem;
        border-radius: 0.5rem;

        &:nth-last-of-type(n + 2) {
          margin-right: 0.4rem;
        }
      }

      .current {
        background-color: $uni-text-color-btn;
      }

      .success {
        background-color: #d3da95;
      }
    }

    .right {
      @include fontStyle(1.7);
      margin-left: 1rem;
      width: 5.3rem;
      height: 2.2rem;
      line-height: 2.2rem;
      text-align: center;
      border-radius: 1.25rem;
      border: #f9eedc solid 1px;
      box-sizing: border-box;
      font-size: 1.4rem;

      .current {
        color: $uni-text-color;
      }

      .total {
        color: $uni-text-color-grey;
      }
    }
  }

  .select-body {
    height: 100%;

    .swiper-item {
      overflow-y: auto;
      padding-left: 2rem;
      padding-right: 2rem;
      box-sizing: border-box;

      .serial_number {
        @include fontStyle(1.5);
        color: #d1bbb2;
        margin-bottom: 1rem;
        line-height: 1;
      }

      &::-webkit-scrollbar {
        display: none;
        width: 0;
        height: 0;
        color: transparent;
      }
    }

    .select-content {
      padding-bottom: calc(10rem + constant(safe-area-inset-bottom));
      padding-bottom: calc(10rem + env(safe-area-inset-bottom));

      .item {
        border: $uni-bg-color-speak solid 2px;
        min-height: 7rem;
        border-radius: 1.5rem;
        display: flex;
        align-items: center;
        padding: 1.25rem 1.5rem;
        background-color: #fff9ef;
        box-sizing: border-box;

        &:nth-child(n + 2) {
          margin-top: 0.8rem;
        }

        .number {
          font-size: 2.6rem;
          color: $uni-text-color;
          font-family: baloo;
          margin-right: 2.2rem;
        }

        .text {
          @include fontStyle(1.5);
          word-break: break-all;
          word-wrap: break-word;
        }

        &.active {
          background-color: #fee1ad;
          border: $uni-btn-border solid 2px;
        }
      }
    }
  }
}
</style>
